#include "GamePrintUtils.h"
#include "Team.h"
#include "Vectors.h"
#include "Global.h"
#include "PrintUtilities.h"
#include "Utilities.h"
#include "Player.h"
#include "Match.h"
#include "Classification.h"
#include "Calendar.h"
#include "League.h"
#include "ServiceProvider.h"
#include "LeagueManager.h"

#include <string>

void PrintPlayerHeader(std::ostream& o_stream)
{
	o_stream << Print::TabUpTo("RL", 3);
	o_stream << Print::TabUpTo("AGE", 4);
	o_stream << Print::TabUpTo("ATK", 4);
	o_stream << Print::TabUpTo("DEF", 4);
	o_stream << Print::TabUpTo("GLK", 4);
	o_stream << Print::TabUpTo("RES", 4);
	o_stream << Print::TabUpTo("NUM", 4);
	o_stream << Print::TabUpTo("GOL", 4);
	o_stream << Print::TabUpTo("DUN", 4);
	o_stream << Print::TabUpTo("SAL", 4);
	o_stream << Print::TabUpTo("BUY", 5);
	o_stream << Print::TabUpTo("SELL", 5);
	o_stream << std::endl;
}

void PrintPlayer(std::ostream& o_stream, const Player& i_player, const int i_role)
{
	o_stream << Print::TabUpTo(i_player.GetName(), Player::GetPlayerParams().MAX_CHAR_PLAYER_NAME);

	if(i_role == Goalkeeper)
		o_stream << Print::TabUpTo("G", 3);
	else if(i_role== Defender)
		o_stream << Print::TabUpTo("D", 3);
	else if(i_role== Attacker)
		o_stream << Print::TabUpTo("A", 3);
	else
		o_stream << Print::TabUpTo("", 3);

	o_stream << Print::TabUpTo(Utilities::IntToString(i_player.GetAge()), 4);
	o_stream << Print::TabUpTo(Utilities::IntToString(i_player.GetSkill(Attacker)), 4);
	o_stream << Print::TabUpTo(Utilities::IntToString(i_player.GetSkill(Defender)), 4);
	o_stream << Print::TabUpTo(Utilities::IntToString(i_player.GetSkill(Goalkeeper)), 4);
	o_stream << Print::TabUpTo(Utilities::IntToString(i_player.GetSkills().m_resistance), 4);
	o_stream << Print::TabUpTo(Utilities::IntToString(i_player.GetPlayedMatch()), 4);
	o_stream << Print::TabUpTo(Utilities::IntToString(i_player.GetScoredGoal()), 4);
	o_stream << Print::TabUpTo(Utilities::IntToString(i_player.GetDaysUnavaiable()), 4);
	o_stream << Print::TabUpTo(Utilities::IntToString(i_player.GetSalary()), 4);
	o_stream << Print::TabUpTo(Utilities::IntToString(i_player.BuyValue()), 5);
	o_stream << Print::TabUpTo(Utilities::IntToString(i_player.SellValue()), 5);
	o_stream << std::endl;
}

void PrintTeam(std::ostream& o_stream, const Team& i_team)
{
	typedef PlayerVecCit Iterator;
	Iterator end = i_team.GetPlayersList().end();
	Iterator begin = i_team.GetPlayersList().begin();
	size_t i = 1;
	o_stream << i_team.GetName() << std::endl << std::endl;
	o_stream << Print::TabUpTo(" ", 4);
	o_stream << Print::TabUpTo("TITOLARS: ", Player::GetPlayerParams().MAX_CHAR_PLAYER_NAME);
	PrintPlayerHeader(o_stream);

	int salarySum = 0;
	for(Iterator It = begin; It != end; ++It)
	{
		static const std::string bracket = ")";
		o_stream << i << Print::TabUpTo(bracket, (i>9 ? 2 : 3));
		PrintPlayer(o_stream, *(*It), Team::GetRoleByIndex(i-1));

		++i;
		if (i == Team::GetParams().TITOLARS_PLAYERS + 1) 
		{
			o_stream << std::endl;
			o_stream << Print::TabUpTo(" ", 4);
			o_stream << Print::TabUpTo("PANCHINARS: ", Player::GetPlayerParams().MAX_CHAR_PLAYER_NAME );
			PrintPlayerHeader(o_stream);
		}
		salarySum += (*It)->GetSalary();
	}
#ifdef VIEW_TEAMS_BUDGET_LOG
	o_stream << "\nBudget: " << Utilities::IntToString(i_team.GetBudget()) << "\t" << "Salary per Match: " <<  salarySum << std::endl;
#endif
}

void PrintMatch(std::ostream& o_stream, const Match& i_match)
{
	const MatchTeamData& data0 = i_match.GetTeamData(0);
	const MatchTeamData& data1 = i_match.GetTeamData(1);
	for (size_t i = data0.m_team->GetName().length(); i <= (Consts::SCREEN_WIDTH / 2 - 5); ++i)
	{
		o_stream << " ";
	}
	o_stream	<< data0.m_team->GetName() << "  " 
				<< data0.m_goals << "-"
				<< data1.m_goals << "  " 
				<< data1.m_team->GetName()			
				<< std::endl;
}

std::string& LeaguePositionToSymbol(const League& i_league, const int i_pos)
{
	static std::string promoted = "+";
	static std::string demoted = "-";
	static std::string none = " ";
	const int numPromoted = i_league.GetNumPromoted();
	const int numDemoted = i_league.GetNumDemoted();
	if(i_pos < numPromoted)
		return promoted;
	if(i_pos >= static_cast<int>(i_league.GetTeams().size()) - numDemoted)
		return demoted;
	return none;
}

void PrintClassification(std::ostream& o_stream, const League& i_league)
{
	using namespace Print;
	const size_t max_char_team_name = Team::GetParams().MAX_CHAR_TEAM_NAME;
	const Classification& classification = *i_league.GetClassification();

	std::string title = "TEAM:";
	o_stream << TabUpTo("ID",6)
		<< TabUpTo("TEAM", max_char_team_name)
		<< TabUpTo("X", 2)
		<< TabUpTo("PTS", 4)
		<< TabUpTo("G", 3)
		<< TabUpTo("W", 3)
		<< TabUpTo("D", 3)
		<< TabUpTo("L", 3)
		<< TabUpTo("GO", 4)
		<< TabUpTo("GI", 4)
		<< TabUpTo("GD", 5)
		<< std::endl;
	PrintDecorationLine(o_stream, '-');
	o_stream << "\n";

	const TeamScoreCollection& teamScores = classification.GetTeamScores();

	for(size_t i = 0; i < teamScores.size(); ++i)
	{
		const TeamScore& teamScore = teamScores.at(i);
		const int goalDifference = teamScore.m_outGoals - teamScore.m_inGoals;
		const int playedMatches = teamScore.m_winMatches + teamScore.m_drawMathes + teamScore.m_lostMatches;
		o_stream << TabUpTo(teamScore.m_team->GetID(), 4)
			<< (teamScore.m_team->IsUserControlled() ? "* " : "  ")
			<< TabUpTo(teamScore.m_team->GetName(), max_char_team_name)
			<< TabUpTo(LeaguePositionToSymbol(i_league, i), 2)
			<< TabUpTo(teamScore.m_score, 4)
			<< TabUpTo(playedMatches, 3)
			<< TabUpTo(teamScore.m_winMatches, 3)
			<< TabUpTo(teamScore.m_drawMathes, 3)
			<< TabUpTo(teamScore.m_lostMatches, 3)
			<< TabUpTo(teamScore.m_outGoals, 4)
			<< TabUpTo(teamScore.m_inGoals, 4)
			<< TabUpTo(goalDifference, 5)
			<< std::endl;
	}
	o_stream << std::endl;
}

void PrintCalendar(std::ostream & o_stream, const League& i_league)
{
	typedef TurnGenerator::Couples::const_iterator Iterator;
	
	const Calendar& calendar = *i_league.GetCalendar();
	const TeamVec& teams = calendar.GetTeamList();

	TurnGenerator::Couples turn;

	for(size_t i = 0; i < (2 * (teams.size() -1)); ++i)
	{
		o_stream << std::endl << "Giornata " << i+1 << ":" << std::endl;

		if(i < i_league.GetCalendar()->GetTurnNumber())
		{
			const MatchVec& scores = i_league.GetClassification()->GetMatchesHistory();
			MatchVecCIt beg = scores.begin() + teams.size()/2 * i;
			MatchVecCIt end = beg + teams.size()/2;
			for(MatchVecCIt it = beg; it != end; ++it)
				PrintMatch(std::cout, *it);
		}
		else
		{
			calendar.GetTurnGenerator().GetTurnNumber(i, turn);
			
			for(Iterator It = turn.begin(); It != turn.end(); ++It)
			{
				std::string firstUserControlled = (teams.at(It->first)->IsUserControlled()) ? "*** " : "";
				std::string secondUserControlled = (teams.at(It->second)->IsUserControlled()) ? "*** " : "";
				o_stream	<< Print::CenterToLeft(firstUserControlled + teams.at(It->first)->GetName() + " -" );
				o_stream	<< " "
							<< secondUserControlled + teams.at(It->second)->GetName() 
							<< std::endl;
			}
		}
	}
	o_stream << std::endl;
}